/*
 * embedded IPsec
 * Copyright (c) 2003 Niklaus Schild and Christian Scheurer, HTI Biel/Bienne
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 */

/** @file sha1_test.c
 *  @brief Test functions for SHA1
 *
 *  @author Christian Scheurer <http://www.christianscheurer.ch> <BR>
 *
 *  <B>OUTLINE:</B>
 *
 *  This file contains test functions used to verify the SHA1 code.
 *
 *  <B>IMPLEMENTATION:</B>
 *
 *  There are no implementation hints to be mentioned.
 *
 *  <B>NOTES:</B>
 *
 * This document is part of <EM>embedded IPsec<BR>
 * Copyright (c) 2003 Niklaus Schild and Christian Scheurer, HTI Biel/Bienne<BR>
 * All rights reserved.</EM><HR>
 */

#include <string.h>

#include "ipsec/util.h"
#include "ipsec/sha1.h"
#include "ipsec/debug.h"
#include "testing/structural/structural_test.h"


/**
 * Test the SHA1_Init() function
 * @return int number of tests failed in this function
 */
int sha1_test_SHA1_Init(void)
{
	int local_error_count = 0;
	int i;
	SHA_CTX      context;

	context.h0  = 0x12345678L;
	context.h1  = 0x12345678L;
	context.h2  = 0x12345678L;
	context.h3  = 0x12345678L;
	context.h1  = 0x12345678L;
	context.Nl  = 0x12345678L;
	context.Nh  = 0x12345678L;
	memset(&context.data, 'X', SHA_LBLOCK*sizeof(SHA_LONG));
	context.num = 0x1234;
		
	SHA1_Init(&context);

	if(context.h0 != 0x67452301UL) local_error_count++;
	if(context.h1 != 0xefcdab89UL) local_error_count++;
	if(context.h2 != 0x98badcfeUL) local_error_count++;
	if(context.h3 != 0x10325476UL) local_error_count++;
	if(context.h4 != 0xc3d2e1f0UL) local_error_count++;
	if(context.Nl != 0x00000000UL) local_error_count++;
	if(context.Nh != 0x00000000UL) local_error_count++;
	if(context.num != 0x0000) 		local_error_count++;
	for(i = 0; i < SHA_LBLOCK; i++) {
		if(context.data[i] != 0x58585858UL) {
			local_error_count++;
			break;
		}
	}

	if(local_error_count != 0) {
		printf("sha1_test_SHA1_init(): error - SHA1_Init(&context) did made %d errors initializing a SHA_CTX data structure\n", local_error_count);
	}

	return local_error_count;
}	
	


/**
 * Test the SHA1_Update() function
 * @return int number of tests failed in this function
 */
int sha1_test_SHA1_Update(void)
{
	unsigned char inputdata_1[65] =
	{
	    0x7C, 0x53, 0x50, 0x53, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
	    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
	    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
	    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
	    0x00, 
	};
	unsigned char inputdata_2[28] =
	{
	    0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x79, 0x61, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, 
	    0x66, 0x6F, 0x72, 0x20, 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x3F, 
	};
	unsigned char context_before_update_1[94] =
	{
	    0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 
	    0xF0, 0xE1, 0xD2, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x30, 0x5A, 0x8B, 
	    0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xC1, 0xCD, 0xC6, 0x21, 0x5A, 0xCD, 0x4A, 
	    0xDC, 0xC1, 0x9D, 0xB7, 0xB4, 0x8E, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	};
	unsigned char context_after_update_1[94] =
	{
	    0xA7, 0x8E, 0x4D, 0x62, 0x03, 0x18, 0x2B, 0x3F, 0xE4, 0xB9, 0x54, 0x95, 0xF5, 0x65, 0xC0, 0x28, 
	    0x8E, 0xB9, 0xFC, 0xA9, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x30, 0x5A, 0x8B, 
	    0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xC1, 0xCD, 0xC6, 0x21, 0x5A, 0xCD, 0x4A, 
	    0xDC, 0xC1, 0x9D, 0xB7, 0xB4, 0x8E, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	};
	unsigned char context_after_update_2[94] =
	{
	    0xA7, 0x8E, 0x4D, 0x62, 0x03, 0x18, 0x2B, 0x3F, 0xE4, 0xB9, 0x54, 0x95, 0xF5, 0x65, 0xC0, 0x28, 
	    0x8E, 0xB9, 0xFC, 0xA9, 0xE0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x61, 0x68, 0x77, 
	    0x20, 0x6F, 0x64, 0x20, 0x77, 0x20, 0x61, 0x79, 0x20, 0x74, 0x6E, 0x61, 0x20, 0x72, 0x6F, 0x66, 
	    0x68, 0x74, 0x6F, 0x6E, 0x3F, 0x67, 0x6E, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 
	};
	int local_error_count = 0;
	SHA_CTX context;

	memcpy(&context, context_before_update_1, sizeof(context_before_update_1));

	SHA1_Update(&context, inputdata_1, sizeof(inputdata_1) - 1);

	if(memcmp(&context, context_after_update_1, sizeof(context_after_update_1) - 1) != 0)
	{
		local_error_count++;
		IPSEC_LOG_TST("sha1_test_SHA1_Update", "FAILURE", ("SHA1_Update() failed")) ;
		printf("     INPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", inputdata_1, 0, sizeof(inputdata_1) - 1);
		printf("     OUTPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", (char*)&context, 0, sizeof(context));
		printf("     EXPECTED OUTPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", context_after_update_1, 0, sizeof(context_after_update_1));
	}

	memcpy(&context, context_after_update_1, sizeof(context_after_update_1));

	SHA1_Update(&context, inputdata_2, sizeof(inputdata_2));

	if(memcmp(&context, context_after_update_2, sizeof(context_after_update_2)) != 0)
	{
		local_error_count++;
		IPSEC_LOG_TST("sha1_test_SHA1_Update", "FAILURE", ("SHA1_Update() failed")) ;
		printf("     INPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", inputdata_2, 0, sizeof(inputdata_2));
		printf("     OUTPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", (char*)&context, 0, sizeof(context));
		printf("     EXPECTED OUTPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", context_after_update_2, 0, sizeof(context_after_update_2));
	}

	return local_error_count;
}




/**
 * Test the SHA1_Final() function
 * @return int number of tests failed in this function
 */
int sha1_test_SHA1_Final(void)
{
	unsigned char context_before_final[94] =
	{
	    0xA7, 0x8E, 0x4D, 0x62, 0x03, 0x18, 0x2B, 0x3F, 0xE4, 0xB9, 0x54, 0x95, 0xF5, 0x65, 0xC0, 0x28, 
	    0x8E, 0xB9, 0xFC, 0xA9, 0xE0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x61, 0x68, 0x77, 
	    0x20, 0x6F, 0x64, 0x20, 0x77, 0x20, 0x61, 0x79, 0x20, 0x74, 0x6E, 0x61, 0x20, 0x72, 0x6F, 0x66, 
	    0x68, 0x74, 0x6F, 0x6E, 0x3F, 0x67, 0x6E, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 
	};
	unsigned char context_after_final[94] =
	{
	    0x44, 0x12, 0x85, 0x98, 0x57, 0x1C, 0xF9, 0x3A, 0xDC, 0xE2, 0x8C, 0xA3, 0x96, 0x87, 0xC3, 0x8E, 
	    0xC4, 0xDE, 0x08, 0x6C, 0xE0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x61, 0x68, 0x77, 
	    0x20, 0x6F, 0x64, 0x20, 0x77, 0x20, 0x61, 0x79, 0x20, 0x74, 0x6E, 0x61, 0x20, 0x72, 0x6F, 0x66, 
	    0x68, 0x74, 0x6F, 0x6E, 0x3F, 0x67, 0x6E, 0x69, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x02, 0x00, 0x00, 0x00, 0x00, 
	};
	unsigned char digest_before_final[20] =
	{
	
	    0x00, 0x00, 0xAC, 0x90, 0x44, 0x67, 0xC0, 0x29, 0x27, 0xFB, 0x60, 0x92, 0xC0, 0x97, 0xFE, 0xAC, 
	    0x1F, 0x30, 0x5A, 0x8B, 
	};
	unsigned char digest_after_final[20] =
	{
	    0x98, 0x85, 0x12, 0x44, 0x3A, 0xF9, 0x1C, 0x57, 0xA3, 0x8C, 0xE2, 0xDC, 0x8E, 0xC3, 0x87, 0x96, 
	    0x6C, 0x08, 0xDE, 0xC4, 
	};
	int 			local_error_count = 0;
	SHA_CTX 		context;
	unsigned char 	digest[20];

	memcpy(&context, context_before_final, sizeof(context_before_final));
	memcpy(&digest, digest_before_final, sizeof(digest_before_final));

    SHA1_Final(digest, &context);

	if(memcmp(&context, context_after_final, sizeof(context_after_final)) != 0)
	{
		local_error_count++;
		IPSEC_LOG_TST("sha1_test_SHA1_Final", "FAILURE", ("context does not match")) ;
		printf("     INPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", context_before_final, 0, sizeof(context_before_final));
		printf("     OUTPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", (char*)&context, 0, sizeof(context));
		printf("     EXPECTED OUTPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", context_after_final, 0, sizeof(context_after_final));
	}

	if(memcmp(&digest, digest_after_final, sizeof(digest_after_final)) != 0)
	{
		local_error_count++;
		IPSEC_LOG_TST("sha1_test_SHA1_Final", "FAILURE", ("digest does not match")) ;
		printf("     INPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", digest_before_final, 0, sizeof(digest_before_final));
		printf("     OUTPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", (char*)&digest, 0, sizeof(digest));
		printf("     EXPECTED OUTPUT:\n") ;
		IPSEC_DUMP_BUFFER("          ", digest_after_final, 0, sizeof(digest_after_final));
	}

	return local_error_count;
}



/**
 * Main test function for the SHA1 tests.
 * It does nothing but calling the subtests one after the other.
 */
void sha1_test(test_result *global_results)
{
	test_result 	sub_results	= {
						 13, 			
						  3,			
						  0, 			
						  0, 			
					};
	int retcode;

	retcode = sha1_test_SHA1_Init();
	IPSEC_TESTING_EVALUATE(retcode, sub_results, "sha1_test_SHA1_Init()", ("ported from openssl.org"));

	retcode = sha1_test_SHA1_Update();
	IPSEC_TESTING_EVALUATE(retcode, sub_results, "sha1_test_SHA1_Update()", ("ported from openssl.org"));

	retcode = sha1_test_SHA1_Final();
	IPSEC_TESTING_EVALUATE(retcode, sub_results, "sha1_test_SHA1_Final()", ("ported from openssl.org"));

	global_results->tests += sub_results.tests;
	global_results->functions += sub_results.functions;
	global_results->errors += sub_results.errors;
	global_results->notimplemented += sub_results.notimplemented;
}


